package jmine.tec.sync;

import java.io.Serializable;
import java.util.List;
import java.util.Map;

import bancosys.tec.persist.Persistable;
import bancosys.tec.persist.dao.BeanNotFoundException;

/**
 * Classes que implementam esta interface sao responsaveis por "materializar" entidades de suas representacoes para alguma classe de dominio
 * 
 * @author takeshi
 * @param <A> o tipo da classe de dominio local
 */
public interface EntityMaterializer<A extends Persistable> {

    /**
     * @return devolve o nome da entidade a ser persistida localmente
     */
    String getLocalEntityName();

    /**
     * @return devolve o nome da entidade origem do sistema remoto
     */
    String getRemoteEntityName();

    /**
     * @return devolve <code>true</code> se as entidades sao mapeadas usando a sua natural key
     */
    boolean isMappedByNaturalKey();

    /**
     * Atualiza a entidade dadas as suas chaves primarias remotas e a natural key
     * 
     * @param remotePrimaryKey {@link Serializable}
     * @param naturalKey {@link Serializable}
     * @return a entidade local
     */
    A updateEntity(Serializable remotePrimaryKey, Serializable naturalKey);

    /**
     * Atualiza a entidade dadas as suas representacoes
     * 
     * @param remotePrimaryKey {@link Serializable}
     * @param representations {@link Map} com as representacoes
     * @return a entidade local
     */
    A updateEntity(Serializable remotePrimaryKey, Map<Class<?>, Object> representations);

    /**
     * Devolve a representacao local de uma entidade, buscando e materializando caso necessario
     * 
     * @param remoteId {@link Serializable}
     * @param naturalKey {@link Serializable}
     * @return a entidade local
     * @throws BeanNotFoundException se nenhuma entidade puder ser localizada e nem obtida remotamente - possivelmente foi removida do
     * sistema remoto
     */
    A getLocalCopyOrRetrieve(Serializable remoteId, Serializable naturalKey) throws BeanNotFoundException;

    /**
     * Apaga a copia local dada a sua chave primaria remota
     * 
     * @param remotePrimaryKey {@link Serializable}
     */
    void entityDeleted(Serializable remotePrimaryKey);

    /**
     * Apaga a copia local de uma entidade dadas a sua chave primaria e a sua natural key (ou null quando nao disponivel)
     * 
     * @param remotePrimaryKey {@link Serializable}
     * @param naturalKey {@link Serializable}
     */
    void entityDeleted(Serializable remotePrimaryKey, Serializable naturalKey);

    /**
     * Seta a dependencia para o {@link DatabaseSynchronizationListener}. Soh deve ser chamado pela propria classe
     * 
     * @param listener {@link DatabaseSynchronizationListener}
     */
    void setDatabaseSynchronizationListener(DatabaseSynchronizationListener listener);

    /**
     * Devolve a natural key esperada da entidada, dadas as suas representacoes REST ou <code>null</code> quando a entidade nao definir
     * natural key ou quando esta nao importar (ex: {@link #isMappedByNaturalKey()} devolve <code>false</code>)
     * 
     * @param remoteId {@link Serializable}
     * @param representations {@link Map}
     * @return {@link Serializable}
     */
    Serializable naturalKeyFromRepresentations(Serializable remoteId, Map<Class<?>, Object> representations);

    /**
     * @return devolve a lista de representacoes necessarias para se criar a entidade localmente
     */
    List<? extends Class<?>> remoteRepresentations();

}
